package com.auth.config.filter;


import com.auth.config.exception.HttpRequestException;
import com.auth.config.token.CustomAuthenticationToken;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author: hw
 * @date: 2021/11/19 10:08
 */
public class HttpAuthenticationEntryPoint extends AbstractAuthenticationProcessingFilter {
    private boolean postOnly = true;
    private static final String IPHONE = "phone";
    private static final String USER = "user";
    /**
     *  设置拦截路径进行Http请求的拦截验证
     *  此匹配方法需要配合 loginProcessingUrl("/login") 一起使用。单独配置此路径并不会有效
     */
    private static final String OAUTH_TOKEN_URL = "/login";
    private static final String HTTP_METHOD_POST = "POST";
    private static final String BASIC = "Basic ";

    public HttpAuthenticationEntryPoint() {
        super(new AntPathRequestMatcher(OAUTH_TOKEN_URL, HTTP_METHOD_POST));
    }

    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler authenticationSuccessHandler){
        super.setAuthenticationSuccessHandler(authenticationSuccessHandler);
    }

    @Override
    public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
      super.setAuthenticationFailureHandler(failureHandler);
    }
    /**
     * 添加未认证用户认证信息，然后在provider里面进行正式认证
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
            throws AuthenticationException{
        if (postOnly && !httpServletRequest.getMethod().equals(HTTP_METHOD_POST)) {
            throw new HttpRequestException("不支持认证方法: " + httpServletRequest.getMethod());
        }
        String appId = this.checkAppIdParameter(httpServletRequest);
        String redirectUrl = this.checkedirectURIParameter(httpServletRequest);
        String authType = this.checkTypeParameter(httpServletRequest);
        String principal = this.checkUsernameParameter(httpServletRequest);
        String credentials;
        if (authType.equals(USER)){
            credentials = this.checkPasswordParameter(httpServletRequest);
        }else {
            credentials = this.checkCodeParameter(httpServletRequest);
        }

        // 客户端信息
        CustomAuthenticationToken authRequest = new CustomAuthenticationToken(appId,redirectUrl,authType,principal,credentials);
        setDetails(httpServletRequest,authRequest);
        // 交给验证客户端
        return this.getAuthenticationManager().authenticate(authRequest);

    }
    private void setDetails(HttpServletRequest request, CustomAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }


    private String  validateHeaderParameter(HttpServletRequest httpServletRequest){
        String headerToken = httpServletRequest.getHeader("Authorization");
        if (StringUtils.isEmpty(headerToken)){
            throw new HttpRequestException("exception subject data");
        }
        if (!headerToken.substring(0,6).equals(BASIC)){
            throw new HttpRequestException("header error");
        }
        return headerToken;
    }

    private String checkTypeParameter(HttpServletRequest httpServletRequest){
        String type = httpServletRequest.getParameter("type");
        if (StringUtils.isEmpty(type)){
            throw new HttpRequestException("type is not null");
        }
        return type;
    }

    private String checkAppIdParameter(HttpServletRequest httpServletRequest){
        String appId = httpServletRequest.getParameter("app_Id");
        if (StringUtils.isEmpty(appId)){
            throw new HttpRequestException("appId is not null");
        }
        return appId;
    }

    private String checkUsernameParameter(HttpServletRequest httpServletRequest){
        String account = httpServletRequest.getParameter("account");
        if (StringUtils.isEmpty(account)){
            throw new HttpRequestException("account is not null");
        }
        return account;
    }


    private String checkPasswordParameter(HttpServletRequest httpServletRequest){
        String password = httpServletRequest.getParameter("password");
        if (StringUtils.isEmpty(password)){
            throw new HttpRequestException("password is not null");
        }
        return password;
    }

    private String checkCodeParameter(HttpServletRequest httpServletRequest){
        String code = httpServletRequest.getParameter("code");
        if (StringUtils.isEmpty(code)){
            throw new HttpRequestException("password is not null");
        }
        return code;
    }


    private String checkedirectURIParameter(HttpServletRequest httpServletRequest){
        String redirect_URI  = httpServletRequest.getParameter("redirect_URI");
        if (StringUtils.isEmpty(redirect_URI)){
            throw new HttpRequestException("redirect_URI is not null");
        }
        return redirect_URI;
    }

}
